import 'package:flutter/foundation.dart';
import 'file_node.dart';

/// # FileExplorerController
///
/// 控制 `FileExplorer` 与 `FileExplorerListView` 的核心状态。
///
/// ## 职责：
/// - 记录 **展开路径集合**、**选中路径**、**加载中路径**；
/// - 管理 **懒加载后的子节点缓存**；
/// - 通过 [childrenRevision] 提供“版本号”机制，让 UI 主动刷新；
///
/// ## 使用场景：
/// - **展开/折叠文件夹**：修改 [expanded]；
/// - **选中文件/目录**：修改 [selectedPath]；
/// - **懒加载子节点**：调用 [cacheChildren] 写入缓存；
/// - **删除/重命名节点**：调用 [clearCacheFor] 清除缓存并刷新；
/// - **UI 刷新机制**：监听 [childrenRevision]，一旦版本号递增，重新构建 UI。
class FileExplorerController {
  // ────────────────────────────── 基本状态 ──────────────────────────────

  /// 已展开的文件夹逻辑路径集合
  /// 例如：`{"src", "src/components"}`
  /// - 外部 UI 可监听其变化来控制展开状态
  final expanded = ValueNotifier<Set<String>>({});

  /// 当前选中的节点逻辑路径
  /// - `null` 表示未选中任何节点
  final selectedPath = ValueNotifier<String?>(null);

  /// 正在进行懒加载 I/O 的路径集合
  /// - 当某目录正在异步加载其子节点时，应加入此集合；
  /// - 加载完成后再移除
  final loading = ValueNotifier<Set<String>>({});

  /// 懒加载完成后的“子节点缓存”
  /// - key：逻辑路径
  /// - value：该目录下的子节点列表
  final Map<String, List<FileNode>> loadedChildren = {};

  /// 目录缓存的“修订号”
  /// - 每次调用 [cacheChildren] / [clearCacheFor] 都会自增
  /// - UI 层监听此值，用于触发刷新（而不是依赖 expanded 变化）
  final ValueNotifier<int> childrenRevision = ValueNotifier<int>(0);

  // ────────────────────────────── 状态序列化/反序列化 ──────────────────────────────

  /// 导出为 Map，方便持久化或跨组件传递
  Map<String, dynamic> toMap() => {
    'expanded': expanded.value.toList(),
    'selectedPath': selectedPath.value,
  };

  /// 判断某路径是否处于展开状态
  bool isExpanded(String path) => expanded.value.contains(path);

  /// 根据外部 Map 恢复状态（常用于持久化还原）
  void applyFromMap(Map<String, dynamic> map) {
    final exp = (map['expanded'] as List?)?.cast<String>() ?? const <String>[];
    expanded.value = {...exp};
    selectedPath.value = map['selectedPath'] as String?;
  }

  // ────────────────────────────── 展开/折叠/选中操作 ──────────────────────────────

  /// 设置某路径的展开/折叠状态
  void setExpanded(String path, bool value) {
    final next = {...expanded.value};
    value ? next.add(path) : next.remove(path);
    expanded.value = next;
  }

  /// 批量展开路径
  void expandAll(Iterable<String> paths) =>
      expanded.value = {...expanded.value, ...paths};

  /// 折叠所有路径
  void collapseAll() => expanded.value = {};

  /// 设置当前选中的路径
  void select(String? path) => selectedPath.value = path;

  /// “显示指定路径”的接口（滚动到可见位置），
  /// 仅占位，实际滚动逻辑应由外部实现。
  void reveal(String path) {/* no-op */}

  // ────────────────────────────── 加载状态 & 缓存管理 ──────────────────────────────

  /// 设置某路径的“加载中”状态
  void setLoading(String path, bool value) {
    final next = {...loading.value};
    value ? next.add(path) : next.remove(path);
    loading.value = next;
  }

  /// 写入子节点缓存并递增版本号，触发 UI 刷新
  void cacheChildren(String path, List<FileNode> children) {
    loadedChildren[path] = children;
    childrenRevision.value++;
  }

  /// 清理缓存
  /// - [includeDescendants] = true 时，连同所有子路径缓存一起清理；
  /// - 每次调用都会递增 [childrenRevision]，触发 UI 刷新
  void clearCacheFor(String path, {bool includeDescendants = true}) {
    loadedChildren.removeWhere(
          (k, _) => k == path || (includeDescendants && k.startsWith('$path/')),
    );
    childrenRevision.value++;
  }
}
